#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"

#define LINE_SIZE 1024
#define ARGC_SIZE 100
#define EXIT_CODE 44

char pwd[LINE_SIZE];
char command_line[LINE_SIZE];
char* _argv[ARGC_SIZE];
char** my_env = NULL;
int last_code = 0;

const char* get_user_name()
{
    return getenv("USER");
}

const char* get_host_name()
{
    return getenv("HOSTNAME");
}

const char* getpwd()
{
    return getcwd(pwd, sizeof(pwd));
}

void my_env_init()
{
    my_env = (char**)malloc(sizeof(*my_env)*ARGC_SIZE);
    int x = 0;
    for(x=0;x<ARGC_SIZE;x++)
    {
        my_env[x] = NULL;
    }
}

void interact(char* cline, int size)
{
    getpwd();
    printf(LEFT"主机名：%s""@""用户名：%s"" ""路径：%s"RIGHT LABLE" ", get_host_name(), get_user_name(), pwd);
    char* ptr = fgets(cline, size-1, stdin); //成功则返回对应字符串，不成功返回空
    assert(ptr);
    cline[strlen(cline)-1] = '\0'; //strlen返回结果不含\0,但fgets末尾是"\n\0",所以要去掉或替换掉\n
    printf("%s\n", command_line);

}

int split_string(char* cline, char* argv[])
{

    int i = 0;
    argv[i++] = strtok(cline, DELIM);
    while(argv[i++] = strtok(NULL, DELIM));

    // 测试用
    //int j = 0;
    //for(;argv[j];j++)
    //{
    //    printf("%s\n", argv[j]);
    //}
    //printf("num = %d\n", i-1);
    
    return i-1;
}

void normal_execute(char* argv[])
{
    pid_t id  = fork();
    if(id < 0)
    {
        perror("fork fail!");
        return;
    }
    else if(id == 0)
    {
        execvp(argv[0], argv);
        exit(EXIT_CODE);
    }
    else
    {
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret == id)
        {
            last_code = WEXITSTATUS(status);
            if(!last_code)
                printf("等待成功\n");
            else
            {
                perror("等待失败\n");
                return;
            }       
        }

    }
}

int build_command(char* argv[], int argc)
{
    if(strcmp(argv[0], "cd")==0 && argc == 2)
    {
        chdir(argv[1]);
        sprintf(getenv("PWD"), "%s", pwd);
        getpwd();
        return 1;
    }
    else if(strcmp(argv[0], "export")==0 && argc == 2)
    {
       int i = 0;
       while(my_env[i] != NULL) i++;
       my_env[i] = (char*)malloc(sizeof(**my_env)*LINE_SIZE);
       strcpy(my_env[i], argv[1]);
       putenv(my_env[i]);
       return 1;
    }
    else if(strcmp(argv[0], "echo")==0 && argc==2)
    {
        if(*argv[1] == '$')
        {
            char* val = getenv(argv[1]+1); //通过$字符后面的环境变量名将环境变量获取
            if(val) printf("%s\n", val);
        }
        else if(strcmp(argv[1], "$?") == 0)
        {
            printf("%d\n", last_code);
            last_code = 0;
        }
        else
        {
            printf("%s\n", argv[1]);
            return 1;
        }

    }

    //特殊处理一下ls
    if(strcmp(argv[0], "ls") == 0)
    {
        argv[argc++] = "--color";
        argv[argc] = NULL;
    }
    return 0;
}

int main()
{
    while(1)
    {
        interact(command_line, sizeof(command_line));
        int argc = split_string(command_line, _argv);
        my_env_init();
        int n = build_command(_argv, argc);
        if(!n)
            normal_execute(_argv);
    }


    return 0;
}
